#pragma once

#include "winboost.hpp"

namespace winboost{
   namespace events {

class event_base
{
   union l_param
   {
      LPARAM   value;
      struct 
      {
         WORD  lo:16;
         WORD  hi:16;
      };
   };

   union w_param
   {
      WPARAM   value;
      struct 
      {
         WORD  lo:16;
         WORD  hi:16;
      };
   };

public:
   event_base(WPARAM w, LPARAM l)
   {
      m_wparam.value = w;
      m_lparam.value = l;
   }

   LPARAM lparam(void) const { return m_lparam.value; }
   WPARAM wparam(void) const { return m_wparam.value; }
   WORD hi_lparam(void) const { return m_lparam.hi; }
   WORD lo_lparam(void) const { return m_lparam.lo; }
   WORD hi_wparam(void) const { return m_wparam.hi; }
   WORD lo_wparam(void) const { return m_wparam.lo; }

protected:
   w_param m_wparam;
   l_param m_lparam; 
};

// windows message event
class message : public event_base
{
public:
   message(UINT msg, WPARAM w, LPARAM l): event_base(w, l)
   , m_message(msg)
   {
   }

   UINT value(void) const  { return m_message; }

private:
   UINT m_message;
};

// Command event for WM_COMMAND
class command : public event_base
{
public:
   command(WPARAM w, LPARAM l): event_base(w, l)
   , m_cmd_id(0)
   , m_accel_id(0)
   , m_hcontrol(NULL)
   , m_ctrl_code(0)
   , m_ctrl_id(0)
   {
      if(m_wparam.hi == 0)
         m_cmd_id = m_wparam.lo;
      else if(m_wparam.hi == 1)
         m_accel_id = m_wparam.lo;
      else
      {
         // control
         m_ctrl_code =  m_wparam.hi;
         m_ctrl_id = m_wparam.lo;
         m_hcontrol = reinterpret_cast<HWND>(m_lparam.value);
      }
   }

   UINT cmd_id(void) const { return m_cmd_id; }
   UINT accel_id(void) const { return m_accel_id; }
   UINT ctrl_code(void) const { return m_ctrl_code; }
   UINT ctrl_id(void) const { return m_ctrl_id; }
   HWND ctrl_hwnd(void) const { return m_hcontrol; }

private:
   UINT m_cmd_id;
   UINT m_accel_id;
   HWND m_hcontrol;
   UINT m_ctrl_code;
   UINT m_ctrl_id;
};

// notification events for WM_NOTIFY
class notification : public event_base
{
public:
   notification(WPARAM w, LPARAM l):event_base(w, l)
   , m_pnmhdr(NULL)
   , m_ctrl_id(0)
   {
      m_ctrl_id = static_cast<UINT>(m_wparam.value);
      m_pnmhdr = reinterpret_cast<NMHDR*>(m_lparam.value);
   }

   NMHDR* hdr(void) const { return m_pnmhdr; }
   UINT ctrl_id(void) const { return m_ctrl_id; }

private:
   NMHDR* m_pnmhdr;
   UINT m_ctrl_id;
};


class cmd_ui
{
public:
   cmd_ui(void):
        m_hmenu(NULL)
      , m_index(-1)
      , m_cmd_id(0)
   {
   }

   HMENU get_menu() const     { return m_hmenu; }
   void set_menu(HMENU val)   { m_hmenu = val; }
   UINT get_cmd_id() const    { return m_cmd_id; }
   void set_cmd_id(UINT val)  { m_cmd_id = val; }
   int get_index() const      { return m_index; }
   void set_index(int val)    { m_index = val; }

   void set_check(bool val)
   {
      if(m_hmenu != NULL && m_index >= 0)
      {
         UINT check = val ? MF_CHECKED : MF_UNCHECKED;
         ::CheckMenuItem(m_hmenu, m_cmd_id, check);
      }
   }

   void enable(bool val)
   {
      UINT en = val ? MF_ENABLED:MF_GRAYED;
      ::EnableMenuItem(m_hmenu, m_cmd_id, en);
   }

   bool is_system_menu(void)
   {
      return m_cmd_id >= 0xF000;
   }

private:
   HMENU m_hmenu;
   int m_index;
   UINT m_cmd_id;
};

typedef boost::signal<LRESULT (const message&)>  sig_msg_event_t; // message callback function
typedef boost::signal<LRESULT (const notification&)>  sig_nfy_event_t; // notification callback function
typedef boost::signal<void (void)>  sig_cmd_event_t; // command callback function
typedef boost::signal<void (cmd_ui&)>      sig_update_ui_event_t; // update ui callback function

typedef boost::shared_ptr<sig_msg_event_t> msg_event_func_ptr_t; // message
typedef boost::shared_ptr<sig_cmd_event_t> cmd_event_func_ptr_t; // command
typedef boost::shared_ptr<sig_nfy_event_t> nfy_event_func_ptr_t; // notification
typedef boost::shared_ptr<sig_update_ui_event_t> update_ui_event_func_ptr_t; // update ui

typedef boost::unordered_map<UINT, msg_event_func_ptr_t> map_messages_t; // message
typedef boost::unordered_map<UINT, cmd_event_func_ptr_t> map_commands_t; // command
typedef boost::unordered_map<UINT, nfy_event_func_ptr_t> map_notify_t;   // notification
typedef boost::unordered_map<UINT, update_ui_event_func_ptr_t> map_update_ui_t; // update ui

   }
}

